import java.util.ArrayList;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Vector;


public class Tree {
	NodeState root;
	ArrayList<NodeState> open;
	Stack<NodeState> close;
	
	float varA, varB, varC, varaA, varaB, varaC, varP;
	
	public Tree(float va, float vb, float vc, float vp, float aa, float ab, float ac) {
		root=null;
		open=new ArrayList<NodeState>();
		close=new Stack<NodeState>();
		varA=va;
		varB=vb;
		varC=vc;
		varaA=aa;
		varaB=ab;
		varaC=ac;
		varP=vp;
		
	}
	
	public void insert(NodeState n, NodeState nf){
		
		if(root==null){
			root=n;
		}
		else {
			n.fatherPointer=nf;
			nf.childrenArray.add(n);
			n.setHeuristicValue(calculateHeuristicValue(n));
		}
	}
	
	public void insertOpen(NodeState n){
		if(open.isEmpty()==true){
			open.add(n);
		}
		else if(open.size()==1){
			if(open.get(0).heuristicValue>=n.heuristicValue){
				open.add(0, n);
			}
			else {
				open.add(1, n);
			}
		}
		else {
			for (int i = 0; i < open.size(); i++) {
				if(n.heuristicValue<=open.get(i).heuristicValue){
					open.add(i, n);
					return;
				}
				
			}			
			open.add(open.size(), n);
		}
	}
	
	public void printDetailedOpen(){
		String cad="Abiertos:\n";
		for (int i = 0; i < open.size(); i++) {
			cad+="Estado "+(i+1)+"\n";
			cad+="Valor Heuristico: "+open.get(i).heuristicValue+"\n";
			cad+="Torre A: "+open.get(i).towerA.toString()+"\n";
			cad+="Torre B: "+open.get(i).towerB.toString()+"\n";
			cad+="Torre C: "+open.get(i).towerC.toString()+"\n\n";
		}
		System.out.println();
		System.out.println(cad);
	}
	
	public void printOpen(){
		String cad="Abiertos:\n";
		for (int i = 0; i < open.size(); i++) {
			cad+="E"+(i+1)+": "+open.get(i).heuristicValue+", ";
		}
		System.out.println();
		System.out.println(cad);
	}
	
	public void printDetailedClose(){
		String cad="Cerrados:\n";
		for (int i = 0; i < close.size(); i++) {
			cad+="Estado "+(i+1)+"\n";
			cad+="Valor Heuristico: "+close.get(i).heuristicValue+"\n";
			cad+="Torre A: "+close.get(i).towerA.toString()+"\n";
			cad+="Torre B: "+close.get(i).towerB.toString()+"\n";
			cad+="Torre C: "+close.get(i).towerC.toString()+"\n\n";
		}
		System.out.println();
		System.out.println(cad);
	}
	
	public void printClose(){
		String cad="Cerrados:\n";
		for (int i = 0; i < close.size(); i++) {
			cad+="E"+(i+1)+": "+close.get(i).heuristicValue+", ";
		}
		System.out.println();
		System.out.println(cad);
	}
	
	public void insertClose(){
		close.push(open.get(open.size()-1));		
		open.remove(open.size()-1);
	}
	
	public short getDeep(NodeState ns){
		short counter=0;
		NodeState aux=ns;
		
		if(ns.fatherPointer==null){
			return counter;
		}
		
		while(aux!=root ){
			aux=aux.fatherPointer;
			counter++;
		}
		return counter;
	}
	
	public float calculateHeuristicValue(NodeState n){
		short deep=getDeep(n);
		short ta=0,tb=0,tc=0;
		
		
		//ciclo para recorrer torre a
		for (int i = 0; i < n.towerA.getSize(); i++) {
			ta+=(n.towerA.getElement(i).size)*varaA;
			if(i<n.towerA.getSize()-1){
				if(n.towerA.getElement(i).size<n.towerA.getElement(i+1).size){
					ta-=varA;
				}
			}
		}		
		
		//ciclo para recorrer torre b
		for (int i = 0; i < n.towerB.getSize(); i++) {
			tb+=(n.towerB.getElement(i).size)*varaB;
			if(i<n.towerB.getSize()-1){
				if(n.towerB.getElement(i).size<n.towerB.getElement(i+1).size){
					tb-=varB;
				}
			}
		}
		
		//ciclo para recorrer torre C
		for (int i = 0; i < n.towerC.getSize(); i++) {
			tc+=(n.towerC.getElement(i).size)*varaC;
			if(i<n.towerC.getSize()-1){
				if(n.towerC.getElement(i).size<n.towerC.getElement(i+1).size){
					tc-=varC;
				}
			}
		}
			
		return ((100-varP))*(ta+tb+tc)+(varP)*(deep);
	}
	
	public boolean isInClose(NodeState n){
		
		for (int i = 0; i < close.size(); i++) {
			if(close.elementAt(i).toStringTowers().compareTo(n.toStringTowers())==0){
				return true;
			}
			
		}		
		return false;
	}
	
	public String fillCloseList(){
		String cad="";
		NodeState aux=root;
		for (int i = 0; i < close.size(); i++) {
			cad+="E"+(i+1)+": "+close.get(i).heuristicValue+"\n";
		}
		/*Vector<String> ret;
		ret=new Vector();
		StringTokenizer row= new StringTokenizer(cad,"\n");
		while(row.hasMoreTokens()){
			ret.add(row.nextToken());
		}*/
		return cad;
	}
	
	public String fillOpenList(){
		String cad="";
		NodeState aux=root;
		for (int i = 0; i < open.size(); i++) {
			cad+="E"+(i+1)+": "+open.get(i).heuristicValue+"\n";
		}
		/*Vector<String> ret;
		ret=new Vector();
		StringTokenizer row= new StringTokenizer(cad,"\n");
		while(row.hasMoreTokens()){
			ret.add(row.nextToken());
		}*/
		return cad;
	}
	
	public void putOfScreen(NodeState r){
		if(r==null) return;
		if(r.childrenArray.size()==0){
			r.x=0;
			r.y=0;
			return ;
		}
		r.x=0;
		r.y=0;
			
		NodeState aux;
		for(int i=0;i<r.childrenArray.size();i++){
			aux=r.childrenArray.get(i);
			aux.x=0;
			aux.y=0;
			putOfScreen(aux);
		}	
	}

	public NodeState getElemntInPosition(int x, int y, NodeState r){
	
		if(r==null) return null;
		if(r.childrenArray.size()==0){
			if ( x>r.x && x<(r.x+50) && y<(r.y+50) && y>r.y){
				return r;
			}
		}
		if ( x>r.x && x<(r.x+50) && y<(r.y+50) && y>r.y){
			return r;
		}
			
		NodeState aux;
		for(int i=0;i<r.childrenArray.size();i++){
			aux=r.childrenArray.get(i);
			if ( x>aux.x && x<(aux.x+50) && y<(aux.y+50) && y>aux.y){
				return aux;
			}
			getElemntInPosition(x, y, aux);
		}
		return null;
	}

}
